﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Web;
using ControlLogNamespace;

namespace BackstageMusiciansFriend
{
    public class ControlHTML
    {
        // El constructor se declara privado porque esta clase no debe
        // ser instanciada.
        private ControlHTML()
        {
        }

        #region Nuevos modulos
        public static ICollection<Product> DoCatalogProcess(string strUrlParam)
        {
            // Variables para la lectura de la página web
            WebResponse response = null;
            StreamReader reader = null;
            List<Product> lstProductos = new List<Product>();
            // Otras variables locales
            string sLinea,
                   sAux;

            string[] sLink = new string[60],
                     sPhoto = new string[60],
                     sPrice = new string[60];

            int i, j, k;

            bool bLink = false,
                 bPrice = false;

            k = 0;

            try
            {
                ControlLog.writeLog("[DoCatalogProcess] Creando conexión a: " + strUrlParam);
                // Apertura de conexión a la página web
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(strUrlParam);
                request.Method = "GET";
                response = request.GetResponse();
                reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);

            }
            catch (Exception ex)
            {
                throw new Exception("Error al crear conexión a: " + strUrlParam + ". Mensaje original: "+ex.Message);
            }

            ControlLog.writeLog("[DoCatalogProcess] Conexión establecida");

            try
            {
                ControlLog.writeLog("[DoCatalogProcess] Exportando Preview de Producto N°:" + (k + 1));
                // Se lee línea por línea y se procesa
                sAux = reader.ReadLine();
                sLinea = HttpUtility.HtmlDecode(sAux);

                while (sLinea != null)
                {
                    #region Procesamiento de la pagina - Spider
                    if (sLinea.Length >= 32)
                    {
                        // Se Busca el link a la página del producto
                        if (sLinea.Substring(10, 22) == "quickView prodThumb120")
                        {
                            i = 22;
                            do
                            {
                                i++;
                            } while (sLinea.Substring(i, 5) != "href=");
                            i += 7;
                            j = i;
                            do
                            {
                                j++;
                            } while (sLinea[j] != '"');

                            sLink[k] = "http://backstage.musiciansfriend.com/" + sLinea.Substring(i, j - i);
                            bLink = true;

                            // La línea siguiente al Link corresponde a la imagen, por lo que se lee y se obtiene el link
                            // para representar en una grilla luego
                            sAux = reader.ReadLine();
                            sLinea = HttpUtility.HtmlDecode(sAux);

                            i = 10;
                            do
                            {
                                i++;
                            } while (sLinea[i] != '"');
                            sPhoto[k] = sLinea.Substring(10, i - 10);
                        }
                        // Por cuestiones de performance, ya que se recorre todo el catálogo,
                        // se obtiene de éste el precio de cada producto
                        if ((sLinea.Substring(0, 12) == "<span class=") && (sLinea.Substring(13, 5) == "price"))
                        {
                            i = j = 20;
                            do
                            {
                                i++;
                            } while (sLinea[i] != '<');

                            sPrice[k] = sLinea.Substring(j, i - j);
                            bPrice = true;
                        }

                        if (bLink && bPrice)
                        {
    //                        TinyProd auxminiprod = new TinyProd();

   //                         auxminiprod.Number = k + 1;
  //                          auxminiprod.Link = sLink[k];
 //                           auxminiprod.Price = sPrice[k];

//                            miniprod[k] = auxminiprod;

                            // Se indica falso en estos flags para que vuelva a buscar hasta el fin del catálogo
                            bLink = bPrice = false;

                            k++;
                        }
                    }


                    sAux = reader.ReadLine();
                    sLinea = HttpUtility.HtmlDecode(sAux);
                    #endregion
                }
            }
            catch (Exception Ex)
            {
                throw new Exception("Error al exportar Preview de Producto N°" + (k + 1) + ": Mensaje original: "+Ex.Message);
            }

            ControlLog.writeLog("[DoCatalogProcess] Todas las Preview de Productos exportadas correctamente");

            i = 0;          
            try
            {                
                ControlLog.writeLog("[DoCatalogProcess] Cantidad de productos a exportar" + k.ToString());

                // Una vez recuperados todos los links de los productos del catálogo, se procede a acceder a cada
                // página en busca del detalle de cada producto
                while (i < k)
                {

                    ControlLog.writeLog("[DoCatalogProcess] Exportando Detalle de Producto N°:" + (i + 1));

                    try
                    {
                        // Se envía a procesar la página del producto a partir de su link
                        Product objProductoObtenido = ProcesarProducto(sLink[i]);
                        objProductoObtenido.Link = sLink[i];
                        objProductoObtenido.Price = sPrice[i];

                        lstProductos.Add(objProductoObtenido);
                        
                    }
                    catch (Exception ee)
                    {
                        ControlLog.writeLog("[DoCatalogProcess] Excepcion armando lista de productos webScrawleados: " + ee.Message + ". Proseguimos...--> en N°:" + (i + 1));

                    }
                    // Se repite la operación por tantos links encontrados en el catálogo
                    i++;
                }



                return lstProductos;

            }
            catch (Exception Ex)
            {
                ControlLog.writeLog("[DoCatalogProcess] Excepcion general procesando catalogo n producto-indice " + (i + 1).ToString() +" - Mensaje: " + Ex.Message);
                throw Ex;
            }
            finally
            {
                if (reader != null)
                    reader.Close();
                if (response != null)
                    response.Close();
            }
        }
        #endregion

        public static String readHtmlPage(string url)
        {

            //setup some variables

            String username = "HERNANTHETEST";
            String password = "poiklj1";

            //setup some variables end

            String result = "";
            String strPost = "user=" + username + "&password=" + password;
            StreamWriter myWriter = null;

            HttpWebRequest objRequest = (HttpWebRequest)WebRequest.Create(url);
            objRequest.Method = "POST";
            objRequest.ContentLength = strPost.Length;
            objRequest.ContentType = "application/x-www-form-urlencoded";

            try
            {
                myWriter = new StreamWriter(objRequest.GetRequestStream());
                myWriter.Write(strPost);
            }
            catch (Exception e)
            {
                return e.Message;
            }
            finally
            {
                myWriter.Close();
            }

            HttpWebResponse objResponse = (HttpWebResponse)objRequest.GetResponse();
            using (StreamReader sr =
               new StreamReader(objResponse.GetResponseStream()))
            {
                result = sr.ReadToEnd();

                // Close and clean up the StreamReader
                sr.Close();
            }
            return result;
        }

        private static string ExtractViewState(string s)
        {
            string viewStateNameDelimiter = "__VIEWSTATE";
            string valueDelimiter = "value=\"";

            int viewStateNamePosition = s.IndexOf(viewStateNameDelimiter);
            int viewStateValuePosition = s.IndexOf(
                  valueDelimiter, viewStateNamePosition
               );

            int viewStateStartPosition = viewStateValuePosition +
                                         valueDelimiter.Length;
            int viewStateEndPosition = s.IndexOf("\"", viewStateStartPosition);

            return HttpUtility.UrlEncodeUnicode(
                     s.Substring(
                        viewStateStartPosition,
                        viewStateEndPosition - viewStateStartPosition
                     )
                  );
        }

        public static string obtenerAccessToken(string sURL)
        {
            if (sURL.Contains("access_token="))
            {

                return sURL.Substring(sURL.IndexOf("access_token=") + 13, sURL.IndexOf("&expires_in") - (sURL.IndexOf("access_token=") + 13));

            }
            else
            {
                throw new System.ArgumentException("La URL no contiene el string access_token", "ML");
            }


        }

        public static void test2()
        {
            byte[] response;

            WebClient webClient = new WebClient();
            response = webClient.DownloadData("https://www.google.com/accounts/ServiceLogin?service=mail&passive=true&rm=false&continue=http%3A%2F%2Fmail.google.com%2Fmail%2F%3Fui%3Dhtml%26zy%3Dl&bsv=llya694le36z&scc=1&ltmpl=default&ltmplcache=2&from=login");

            string viewstate = ExtractViewState(
                  Encoding.ASCII.GetString(response)
               );

            string postData = String.Format(
               "__VIEWSTATE={0}&Email={1}&Passwd={2}&signIn=Login",
               viewstate, "hernan.zbucki@gmail.com", "9dvjjvd9");

            webClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
            response = webClient.UploadData(
                    "https://www.google.com/accounts/ServiceLogin?service=mail&passive=true&rm=false&continue=http%3A%2F%2Fmail.google.com%2Fmail%2F%3Fui%3Dhtml%26zy%3Dl&bsv=llya694le36z&scc=1&ltmpl=default&ltmplcache=2&from=login", "POST", Encoding.ASCII.GetBytes(postData)
                );
        }

        public static Product[] ProcesarCatalogo(string sUrl, ref int iCant, ref TinyProd[] miniprod)
        {
            // Variables para la lectura de la página web
            WebResponse response = null;
            StreamReader reader = null;

            // Otras variables locales
            string sLinea,
                   sAux;

            string[] sLink = new string[60],
                     sPhoto = new string[60],
                     sPrice = new string[60];

            int i, j, k;

            bool bLink = false,
                 bPrice = false;

            k = 0;

            try
            {
                ControlLog.writeLog("[Conectar a Musician's Friend] Creando conexión a: " + sUrl);
                // Apertura de conexión a la página web
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(sUrl);
                request.Method = "GET";
                response = request.GetResponse();
                reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);

            }
            catch (Exception ex)
            {
                throw new ArgumentException("Error al crear conexión a: " + sUrl);
            }

            ControlLog.writeLog("[Conectar a Musician's Friend] Conexión establecida");

            try
            {
                ControlLog.writeLog("[Exportar Productos] Exportando Preview de Producto N°:" + (k + 1));
                // Se lee línea por línea y se procesa
                sAux = reader.ReadLine();
                sLinea = HttpUtility.HtmlDecode(sAux);

                while (sLinea != null)
                {
                    #region Procesamiento de la pagina - Spider
                    if (sLinea.Length >= 32)
                    {
                        // Se Busca el link a la página del producto
                        if (sLinea.Substring(10, 22) == "quickView prodThumb120")
                        {
                            i = 22;
                            do
                            {
                                i++;
                            } while (sLinea.Substring(i, 5) != "href=");
                            i += 7;
                            j = i;
                            do
                            {
                                j++;
                            } while (sLinea[j] != '"');

                            sLink[k] = "http://backstage.musiciansfriend.com/" + sLinea.Substring(i, j - i);
                            bLink = true;

                            // La línea siguiente al Link corresponde a la imagen, por lo que se lee y se obtiene el link
                            // para representar en una grilla luego
                            sAux = reader.ReadLine();
                            sLinea = HttpUtility.HtmlDecode(sAux);

                            i = 10;
                            do
                            {
                                i++;
                            } while (sLinea[i] != '"');
                            sPhoto[k] = sLinea.Substring(10, i - 10);
                        }
                        // Por cuestiones de performance, ya que se recorre todo el catálogo,
                        // se obtiene de éste el precio de cada producto
                        if ((sLinea.Substring(0, 12) == "<span class=") && (sLinea.Substring(13, 5) == "price"))
                        {
                            i = j = 20;
                            do
                            {
                                i++;
                            } while (sLinea[i] != '<');

                            sPrice[k] = sLinea.Substring(j, i - j);
                            bPrice = true;
                        }

                        if (bLink && bPrice)
                        {
                            TinyProd auxminiprod = new TinyProd();

                            auxminiprod.Number = k + 1;
                            auxminiprod.Link = sLink[k];
                            auxminiprod.Price = sPrice[k];

                            miniprod[k] = auxminiprod;

                            // Se indica falso en estos flags para que vuelva a buscar hasta el fin del catálogo
                            bLink = bPrice = false;

                            k++;
                        }
                    }


                    sAux = reader.ReadLine();
                    sLinea = HttpUtility.HtmlDecode(sAux);
                    #endregion
                }
            }
            catch (Exception Ex)
            {
                throw new ArgumentException("Error al exportar Preview de Producto N°" + (k + 1));
            }

            ControlLog.writeLog("[Exportar Productos] Todas las Preview de Productos exportadas correctamente");

            i = 0;
            iCant = k;
            int intProdIndex = 0;
            try
            {
                // Objeto donde se guardará el detalle de cada producto
                Product[] prod = new Product[iCant];
                ControlLog.writeLog("[Exportando Productos] Cantidad de productos a exportar" + (iCant));
                
                // Una vez recuperados todos los links de los productos del catálogo, se procede a acceder a cada
                // página en busca del detalle de cada producto
                while (i < iCant)
                {

                    ControlLog.writeLog("[Exportando Productos] Exportando Detalle de Producto N°:" + (i + 1));

                    try
                    {
                        // Se envía a procesar la página del producto a partir de su link
                        prod[intProdIndex] = ProcesarProducto(sLink[i]);

                        // Si no se encontró algún dato (estos pueden ser Header, Bottom y/o Specifications)
                        // se completa ese campo con "N/D"
                        if (prod[intProdIndex].Features == null)
                            prod[intProdIndex].Features = "N/D";
                        if (prod[intProdIndex].Header == null)
                            prod[intProdIndex].Header = "N/D";
                        if (prod[intProdIndex].Bottom == null)
                            prod[intProdIndex].Bottom = "N/D";
                        if (prod[intProdIndex].Specifications == null)
                            prod[intProdIndex].Specifications = "N/D";

                        // Como el link y el precio se obtuvieron del catálogo, se cargan ahora en el producto
                        prod[intProdIndex].Link = sLink[i];
                        prod[intProdIndex].Price = sPrice[i];
                        intProdIndex++;
                    }
                    catch (Exception ee) 
                    {
                        ControlLog.writeLog("[Exportando Productos] Excepcion cacheada: "+ee.Message+". Proseguimos...--> en N°:" + (i + 1));

                    }
                    // Se repite la operación por tantos links encontrados en el catálogo
                    i++;
                }

                iCant = intProdIndex;
                
                return prod;

            }
            catch (Exception Ex)
            {
                ControlLog.writeLog("[Exportando Productos] Excepcion " + Ex.Message );
                throw new ArgumentException("Error al exportar Detalle de Producto N°" + (i + 1));
            }
            finally
            {
                if (reader != null)
                    reader.Close();
                if (response != null)
                    response.Close();
            }
        }

        private static Product ProcesarProducto(string sUrl)
        {
            // Variables para la lectura de la página web
            WebResponse response = null;
            StreamReader reader = null;

            // Objeto donde se almacenará la información de cada producto
            Product prod = new Product();

            // Otras variables locales
            string sLinea,
                   sAux;

            ProdPart iResul;

            try
            {
                ControlLog.writeLog("[Conectar a Producto de Musician's Friend] Creando conexión a: " + sUrl);
                // Apertura de conexión a la página web
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(sUrl);
                request.Method = "GET";
                response = request.GetResponse();
                reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
            }
            catch (Exception ex)
            {
                throw new ArgumentException("Error al crear conexión a: " + sUrl);
            }

            ControlLog.writeLog("[Conectar a Producto de Musician's Friend] Conexión establecida");

            try
            {
                // Se lee línea por línea y se procesa
                sAux = reader.ReadLine();
                sLinea = HttpUtility.HtmlDecode(sAux);

                while (sLinea != null)
                {
                    iResul = VerificarTipoLineaProducto(sLinea);

                    switch (iResul)
                    {
                        case ProdPart.Title:
                            if (sLinea.Length == 15)
                            {
                                sAux = reader.ReadLine();
                                sLinea = HttpUtility.HtmlDecode(sAux);
                            }
                            prod.Title = ParsearLineaProducto(sLinea, ProdPart.Title);
                            break;

                        case ProdPart.Images:
                            while (sLinea != "</ul>")
                            {
                                if (sLinea.Length > 8)
                                {
                                    if (sLinea.Substring(0, 8) == "<a href=")
                                    {
                                        prod.Images += ParsearLineaProducto(sLinea, ProdPart.Images) + ",";
                                    }
                                }
                                sAux = reader.ReadLine();
                                sLinea = HttpUtility.HtmlDecode(sAux);
                            }
                            break;

                        case ProdPart.Header:
                            if (sLinea.Length == 20)
                            {
                                sAux = reader.ReadLine();
                                sLinea = HttpUtility.HtmlDecode(sAux);
                            }
                            prod.Header = ParsearLineaProducto(sLinea, ProdPart.Header);
                            prod.Header = prod.Header.Replace(';', ',');
                            prod.Header = prod.Header.Replace("'", " ");
                            break;

                        case ProdPart.Description:
                            if (sLinea.Length == 23)
                            {
                                sAux = reader.ReadLine();
                                sLinea = HttpUtility.HtmlDecode(sAux);
                            }
                            prod.Description = ParsearLineaProducto(sLinea, ProdPart.Description);
                            prod.Description = prod.Description.Replace(';', ',');
                            prod.Description = prod.Description.Replace("'", " ");
                            break;

                        case ProdPart.Features:
                            while (sLinea.Substring(0, 4) != "<li>")
                            {
                                sAux = reader.ReadLine();
                                sLinea = HttpUtility.HtmlDecode(sAux);
                            }
                            prod.Features = ParsearLineaProducto(sLinea, ProdPart.Features);
                            prod.Features = prod.Features.Replace(';', ',');
                            prod.Features = prod.Features.Replace("'", " ");
                            break;

                        case ProdPart.Bottom:
                            if (sLinea.Length == 26)
                            {
                                sAux = reader.ReadLine();
                                sLinea = HttpUtility.HtmlDecode(sAux);
                            }
                            prod.Bottom = ParsearLineaProducto(sLinea, ProdPart.Bottom);
                            prod.Bottom = prod.Bottom.Replace(';', ',');
                            prod.Bottom = prod.Bottom.Replace("'", " ");
                            break;

                        case ProdPart.Specifications:
                            while (sLinea.Substring(0, 4) != "<li>")
                            {
                                sAux = reader.ReadLine();
                                sLinea = HttpUtility.HtmlDecode(sAux);
                            }
                            while (sLinea != "</ul>")
                            {
                                prod.Specifications += ParsearLineaProducto(sLinea, ProdPart.Specifications) + "</li><li>";
                                prod.Specifications = prod.Specifications.Replace(';', ',');
                                prod.Specifications = prod.Specifications.Replace("'", " ");
                                sAux = reader.ReadLine();
                                sLinea = HttpUtility.HtmlDecode(sAux);
                            }
                            break;

                        case ProdPart.Other:
                            break;
                    }

                    sAux = reader.ReadLine();
                    sLinea = HttpUtility.HtmlDecode(sAux);
                }


                // Si no se encontró algún dato (estos pueden ser Header, Bottom y/o Specifications)
                // se completa ese campo con "N/D"
                if (prod.Features == null)
                    prod.Features = "N/D";
                if (prod.Header == null)
                    prod.Header = "N/D";
                if (prod.Bottom == null)
                    prod.Bottom = "N/D";
                if (prod.Specifications == null)
                    prod.Specifications = "N/D";
                
                return prod;
            }
            catch (Exception Ex)
            {
                throw new ArgumentException("Error obteniendo datos del producto: " + sUrl);
            }
            finally
            {
                if (reader != null)
                    reader.Close();
                if (response != null)
                    response.Close();
                prod = null;
            }
        }

        private static ProdPart VerificarTipoLineaProducto(string cadena)
        {
            if (cadena.Length < 10)
                return ProdPart.Other;

            if (cadena.Substring(0, 10) == "<h1 class=")
                return ProdPart.Title;

            if (cadena.Length < 17)
                return ProdPart.Other;

            if (cadena.Substring(0, 17) == "<h4>Features</h4>")
                return ProdPart.Features;

            if (cadena.Length < 20)
                return ProdPart.Other;

            if ((cadena.Substring(0, 10) == "<h3 class=") && (cadena.Substring(11, 7) == "heading"))
                return ProdPart.Header;

            if (cadena.Length < 23)
                return ProdPart.Other;

            if ((cadena.Substring(0, 9) == "<p class=") && (cadena.Substring(10, 11) == "description"))
                return ProdPart.Description;

            if (cadena.Length < 26)
                return ProdPart.Other;

            if ((cadena.Substring(0, 11) == "<div class=") && (cadena.Substring(12, 12) == "callToAction"))
                return ProdPart.Bottom;

            if ((cadena.Substring(0, 8) == "<div id=") && (cadena.Substring(9, 14) == "specifications"))
                return ProdPart.Specifications;

            if ((cadena.Substring(0, 11) == "<div class=") && (cadena.Substring(12, 10) == "tabContent"))
                return ProdPart.Images;

            return ProdPart.Other;
        }

        private static string ParsearLineaProducto(string cadena, ProdPart tipo)
        {
            int i, j;
            string sResul = null;

            switch (tipo)
            {
                case ProdPart.Title:
                    if (cadena.Substring(0, 10) == "<h1 class=")
                    {
                        i = j = 15;
                        do
                        {
                            i++;
                        } while (cadena[i] != '<');
                        sResul = cadena.Substring(j, i - j);
                    }
                    else
                    {
                        i = j = 20;
                        do
                        {
                            i++;
                        } while (cadena[i] != '<');
                        sResul = cadena.Substring(j, i - j);
                        j = i + 7;
                        do
                        {
                            j++;
                        } while (cadena[j] != '<');
                        sResul += cadena.Substring(i + 7, j - i - 7);
                    }
                    break;
                case ProdPart.Images:
                    i = 8;
                    do
                    {
                        i++;
                    } while (cadena.Substring(i, 4) != "rel=");
                    i = i + 5;
                    j = i;
                    do
                    {
                        j++;
                    } while (cadena[j] != '|');
                    sResul = cadena.Substring(i, j - i);
                    break;

                case ProdPart.Header:
                    if (cadena.Substring(0, 3) == "<p>")
                        i = j = 3;
                    else
                        i = j = 20;
                    do
                    {
                        i++;
                    } while (cadena[i] != '<');
                    sResul = cadena.Substring(j, i - j);
                    break;

                case ProdPart.Description:
                    i = j = 23;
                    do
                    {
                        i++;
                    } while (cadena.Substring(i, 4) != "</p>");
                    sResul = cadena.Substring(j, i - j);
                    break;

                case ProdPart.Features:
                    sResul = cadena;
                    break;

                case ProdPart.Bottom:
                    if (cadena.Substring(0, 3) == "<p>")
                        i = j = 3;
                    else
                        i = j = 26;
                    do
                    {
                        i++;
                    } while (cadena[i] != '<');
                    sResul = cadena.Substring(j, i - j);
                    break;

                case ProdPart.Specifications:
                    sResul = cadena;
                    break;
            }
            return sResul;
        }
    }
}